import { index } from './utils';
import { cloneDeep, random } from 'lodash';

export type ChessItem = 'X' | 'O' | undefined;
export type ChessItemNonNull = NonNullable<ChessItem>;
export type ChessBoard = ChessItem[][];
export function getEmptyChessBoard(): ChessBoard {
  return index(3).map(() => index(3).map(() => undefined));
}
export function flipChessItem(item: ChessItemNonNull): ChessItemNonNull {
  return item === 'X' ? 'O' : 'X';
}
export function getWinner(board: ChessBoard): { winner: ChessItem } | undefined {
  const lines = [
    ...board,
    ...index(3).map((i) => board.map((row) => row[i])),
    index(3).map((i) => board[i][i]),
    index(3).map((i) => board[2 - i][i]),
  ];
  const winnerLine = lines.find(
    (line) => line.every((item) => item === 'X') || line.every((item) => item === 'O')
  );
  if (winnerLine) {
    return { winner: winnerLine[0] };
  }
  return board.every((row) => row.every((item) => item !== undefined))
    ? { winner: undefined }
    : undefined;
}

export function aiNextStep(
  board: ChessBoard,
  nextItem: ChessItemNonNull
): { x: number; y: number } {
  const emptyCells = index(3)
    .flatMap((i) => index(3).map((j) => ({ x: i, y: j })))
    .filter(({ x, y }) => board[x][y] === undefined);
  const nextSteps = emptyCells.map(({ x, y }) => {
    const nextBoard = cloneDeep(board);
    nextBoard[x][y] = nextItem;
    return { x, y, winner: getWinner(nextBoard)?.winner };
  });
  const winnerStep = nextSteps.find(({ winner }) => winner === nextItem);
  if (winnerStep) {
    return winnerStep;
  }
  const otherNextSteps = emptyCells.map(({ x, y }) => {
    const nextBoard = cloneDeep(board);
    nextBoard[x][y] = flipChessItem(nextItem);
    return { x, y, winner: getWinner(nextBoard)?.winner };
  });
  const otherStep = otherNextSteps.find(({ winner }) => winner !== undefined);
  if (otherStep) {
    return otherStep;
  }
  return nextSteps[random(nextSteps.length - 1)];
}
